using MEC;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace hole.speedrungame
{
	public class GameManager : BaseGameManager
	{
		[Serializable]
		public class EditorReferences
		{
			public Hole holePrefab;
		}

		public static GameManager InstanceMode = null;

		public const int GAME_DURATION_IN_SECONDS = 120;

		private static readonly int[] XP_TABLE = new int[22]
		{
			0,
			10,
			17,
			24,
			31,
			38,
			45,
			52,
			59,
			66,
			73,
			80,
			87,
			94,
			101,
			108,
			115,
			122,
			129,
			136,
			-1,
			-1
		};

		private static readonly int[] POINTS_PER_SIZE_TABLE = new int[21]
		{
			0,
			1,
			2,
			3,
			4,
			5,
			6,
			7,
			8,
			9,
			10,
			11,
			12,
			13,
			14,
			16,
			18,
			20,
			23,
			28,
			30
		};

		public static readonly int[] STAR_REWARD_TABLE = new int[8]
		{
			100,
			50,
			30,
			20,
			8,
			5,
			1,
			0
		};

		public static readonly float[] STAR_REWARD_THRESHOLD_TABLE = new float[8]
		{
			0.99f,
			0.95f,
			0.9f,
			0.8f,
			0.7f,
			0.5f,
			0.2f,
			0f
		};

		[SerializeField]
		public EditorReferences references = new EditorReferences();

		private Map _currentMap;

		private int _totalPoints;

		private List<FallingObject> _fallingObjects = new List<FallingObject>();

		protected override void Awake()
		{
			base.Awake();
			InstanceMode = this;
			if (App.Instance == null)
			{
				SceneManager.LoadScene("Home");
			}
		}

		private void Start()
		{
			GameInit();
		}

		public override void GameInit()
		{
			base.GameInit();
			_hasGameLoaded = false;
			_hasGameStarted = false;
			_hasGameEnded = false;
			UIManager.Instance.LoadingComponent.SetTips(GetRandomTips());
			UIManager.Instance.LoadingComponent.SetLoadingImage(MapManager.Instance.CurrentMap.loadingSprite);
			UIManager.Instance.LoadingComponent.SetModeDescription(GameModeManager.Instance.CurrentMode.loadingTitle, GameModeManager.Instance.CurrentMode.loadingDescription);
			UIManager.Instance.OnGameInit();
			UIManager.Instance.TimerComponent.SetTime(120);
			UIManager.Instance.ProgressionComponent.SetProgression(0, 1);
			UIManager.Instance.ProgressionComponent.SetBest(PlayerData.Instance.GetBestScore(GameModeManager.Instance.CurrentMode.id));
			Timing.RunCoroutine(LoadGameCoroutine());
		}

		public void CountdownStart()
		{
			UIManager.Instance.OnGameStart();
			Timing.RunCoroutine(CountdownCoroutine().CancelWith(base.gameObject), Segment.LateUpdate);
		}

		public override void GameStart()
		{
			_hasGameStarted = true;
			foreach (Hole currentHole in _currentHoles)
			{
				currentHole.GetComponent<HoleController>().CanMove = true;
			}
			UIManager.Instance.TimerComponent.gameObject.SetActive(value: true);
			UIManager.Instance.ProgressionComponent.gameObject.SetActive(value: true);
			Timing.RunCoroutine(GameCoroutine().CancelWith(base.gameObject), Segment.LateUpdate);
		}

		public override void GameEnd()
		{
			if (_hasGameEnded)
			{
				return;
			}
			base.GameEnd();
			_hasGameEnded = true;
			foreach (Hole currentHole in _currentHoles)
			{
				currentHole.GetComponent<HoleController>().CanMove = false;
			}
			float num = Mathf.Clamp01((float)_currentHole.Points / (float)_totalPoints);
			UIManager.Instance.GameOverComponent.SetColor(_currentHole.CurrentSkinParameters.mainColor);
			UIManager.Instance.GameOverComponent.SetScore(num);
			float num2 = Mathf.Floor(num * 10000f) / 100f;
			if (num2 > PlayerData.Instance.GetBestScore(GameModeManager.Instance.CurrentMode.id))
			{
				PlayerData.Instance.SetBestScore(GameModeManager.Instance.CurrentMode.id, num2);
				PlayerData.Instance.SaveData();
			}
			int num3 = 0;
			for (int i = 0; i < STAR_REWARD_THRESHOLD_TABLE.Length; i++)
			{
				if (num >= STAR_REWARD_THRESHOLD_TABLE[i])
				{
					num3 = i;
					break;
				}
			}
			_reward = STAR_REWARD_TABLE[num3];
			RankManager.Instance.AddXpReward(_reward);
			UIManager.Instance.OnGameEnd();
			CheckEndGameAchievements();
			//if (PlayerData.Instance.Vibrations)
			//{
			//	VibrationUtils.StrongVibrate();
			//}
		}

		public override void RegisterFallingObject(FallingObject fo)
		{
			FallingObjectBehaviour fallingObjectBehaviour = null;
			fallingObjectBehaviour = ((!fo.PooledObject) ? ((FallingObjectBehaviour)fo.gameObject.AddComponent<DestroyableFallingObject>()) : ((FallingObjectBehaviour)fo.gameObject.AddComponent<DeactivableFallingObject>()));
			fallingObjectBehaviour.SetGameManager(this);
			fallingObjectBehaviour.SetFallingObject(fo);
			_totalPoints += fallingObjectBehaviour.FallingObject.Points;
			_fallingObjects.Add(fo);
		}

		public override void UnregisterFallingObject(FallingObject fo)
		{
			if (!_hasGameStarted)
			{
				_totalPoints -= fo.Points;
				_fallingObjects.Remove(fo);
			}
			else if (!_hasGameEnded && _fallingObjects.Contains(fo))
			{
				_totalPoints -= fo.Points;
				_fallingObjects.Remove(fo);
			}
		}

		private IEnumerator<float> LoadGameCoroutine()
		{
			string sceneName = MapManager.Instance.CurrentMap.gameScene;
			AsyncOperation async = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
			while (!async.isDone)
			{
				UIManager.Instance.LoadingComponent.UpdateLoading(async.progress * 0.8f);
				yield return Timing.WaitForSeconds(0.2f);
			}
			_hasGameLoaded = true;
			UIManager.Instance.LoadingComponent.UpdateLoading(0.9f);
			yield return Timing.WaitForSeconds(1f);
			_currentMap = UnityEngine.Object.FindObjectOfType<Map>();
			_currentMap.Rotate(90 * UnityEngine.Random.Range(0, 4));
			List<Transform> spawnPoints = new List<Transform>(_currentMap.GetSpawnPoints(UnityEngine.Random.Range(0, _currentMap.spawnPoints.Length)));
			spawnPoints.Shuffle_Fisher_Yates();
			int spawnIndex = 0;
			Hole h = UnityEngine.Object.Instantiate(references.holePrefab, Vector3.zero, Quaternion.identity);
			h.gameObject.name = "Player Local";
			h.gameObject.AddComponent<HoleJoystickController>();
			h.transform.position = spawnPoints[spawnIndex].position;
			h.PlayerId = 0;
			h.IsLocalPlayer = true;
			h.SetPseudo(PlayerData.Instance.Pseudo);
			h.SetSkin(SkinManager.Instance.GetSkinWithIndex(App.Instance.currentSkinIndex));
			h.SetLevel((!App.Instance.enableBigStart) ? 1 : 2);
			h.SetHoleLayerIndex(6);
			h.ShowCrown(s: false);
			h.SetRank(RankManager.Instance.CachedRank);
			h.OnLevelChanged.AddListener(OnHoleLevelUp);
			_currentHole = h;
			_currentHoles.Add(h);
			_currentHoleDictionary.Add(0, h);
			CameraManager.Instance.SetTarget(h.transform);
			TransparencyManager.Instance.SetTarget(h.transform);
			UIManager.Instance.LoadingComponent.UpdateLoading(1f);
			yield return Timing.WaitForSeconds(1f);
			CountdownStart();
		}

		private IEnumerator<float> CountdownCoroutine()
		{
			int countdown = 3;
			UIManager.Instance.CountdownComponent.Show();
			UIManager.Instance.CountdownComponent.SetCountdown(countdown);
			while (countdown > 0)
			{
				yield return Timing.WaitForSeconds(1f);
				countdown--;
				UIManager.Instance.CountdownComponent.SetCountdown(countdown);
			}
			GameStart();
			yield return Timing.WaitForSeconds(0.5f);
			UIManager.Instance.CountdownComponent.Hide();
		}

		private IEnumerator<float> GameCoroutine()
		{
			int gameDuration = 120;
			while (gameDuration > 0 && !_hasGameEnded)
			{
				yield return Timing.WaitForSeconds(1f);
				gameDuration--;
				UIManager.Instance.TimerComponent.SetTime(gameDuration);
				switch (gameDuration)
				{
				case 1:
				case 2:
				case 3:
				case 4:
				case 5:
				case 10:
				case 30:
				case 60:
					UIManager.Instance.AlertRemainingTime(gameDuration);
					break;
				}
			}
			GameEnd();
		}

		public override void ProcessCapture(FallingObjectBehaviour fob, int holeId)
		{
			if (!_hasGameEnded)
			{
				_fallingObjects.Remove(fob.FallingObject);
				Hole currentHole = _currentHole;
				currentHole.AddXp(POINTS_PER_SIZE_TABLE[fob.FallingObject.Points], XP_TABLE[currentHole.Level], XP_TABLE[currentHole.Level + 1]);
				currentHole.AddPoints(fob.FallingObject.Points);
				UIManager.Instance.ProgressionComponent.SetProgression(Mathf.Clamp(currentHole.Points, 0, _totalPoints), _totalPoints);
				UIManager.Instance.FloatingTextComponent.ShowText($"+{(float)fob.FallingObject.Points / (float)_totalPoints * 100f:0.00}%");
				FallingObject.FallingObjectType objectType = fob.FallingObject.ObjectType;
				if (objectType == FallingObject.FallingObjectType.Animal)
				{
					CheckAnimalsAchievement(fob.FallingObject.ObjectTags[0], fob.FallingObject.ObjectTags[1]);
				}
				if ((float)currentHole.Points / (float)_totalPoints >= 1f)
				{
					GameEnd();
				}
			}
		}

		public override void ProcessKill(int killerHoleId, int victimHoleId)
		{
		}

		public void OnHoleLevelUp(int level)
		{
			float t = (float)(level - 1) / 19f;
			CameraManager.Instance.SetDistance(Mathf.Lerp(13f, 175f, t), Mathf.Lerp(16f, 130f, t));
			UIManager.Instance.FloatingTextComponent.ShowLevelUp(_currentHole.CurrentSkinParameters.mainColor, level == 20);
		}
	}
}
